package org.numenta.nupic.examples.cortical_io.breakingnews; import io.cortical.fx.webstyle.CorticalLogoBackground; import io.cortical.fx.webstyle.LabelledRadiusPane; import io.cortical.fx.webstyle.RadiusFlipPane; import io.cortical.fx.webstyle.SegmentedButtonBar; import io.cortical.fx.webstyle.example.DualPanel; import io.cortical.fx.webstyle.example.FingerprintPane; import io.cortical.fx.webstyle.example.LogoTitlePane; import io.cortical.fx.webstyle.example.TriplePanel; import javafx.application.Platform; import javafx.beans.property.BooleanProperty; import javafx.beans.property.IntegerProperty; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleDoubleProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.StringProperty; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Node; import javafx.scene.chart.CategoryAxis; import javafx.scene.chart.LineChart; import javafx.scene.chart.NumberAxis; import javafx.scene.chart.XYChart; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.TextArea; import javafx.scene.control.ToggleButton; import javafx.scene.control.ToggleGroup; import javafx.scene.layout.Background; import javafx.scene.layout.BackgroundFill; import javafx.scene.layout.BorderPane; import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.scene.text.Font; import javafx.scene.text.FontWeight; import javafx.util.Pair; public class BreakingNewsDemoView extends GridPane { enum Mode { AUTO, MANUAL }; enum FlipState { ON_FRONT, ON_BACK }; private Button runOneBtn; private LineChart<String, Number> chart; private XYChart.Series<String, Number> series; private Mode mode = Mode.AUTO; private FlipState state = FlipState.ON_FRONT; private ObjectProperty<Pair<TextArea, TextArea>> inputPaneProperty = new SimpleObjectProperty<>(); private BooleanProperty startActionProperty = new SimpleBooleanProperty(false); private ObjectProperty<Mode> autoModeProperty = new SimpleObjectProperty<Mode>(mode); private IntegerProperty runOneProperty = new SimpleIntegerProperty(-1); private ObjectProperty<XYChart.Series<String, Number>> chartSeriesProperty = new SimpleObjectProperty<>(); private BooleanProperty runDisableProperty = new SimpleBooleanProperty(true); private ObjectProperty<RadiusFlipPane> flipPaneProperty = new SimpleObjectProperty<>(); private ObjectProperty<FlipState> flipStateProperty = new SimpleObjectProperty<FlipState>(state); private ObjectProperty<TriplePanel> fingerprintPanelProperty = new SimpleObjectProperty<TriplePanel>(); private ObjectProperty<TextArea> leftActivityPanelProperty = new SimpleObjectProperty<>(); private ObjectProperty<TextArea> rightActivityPanelProperty = new SimpleObjectProperty<>(); private ObjectProperty<StringProperty> currentLabelProperty = new SimpleObjectProperty<>(); private ObjectProperty<Label> queueDisplayProperty = new SimpleObjectProperty<>(); public BreakingNewsDemoView() { setBackground(new Background(new BackgroundFill(Color.WHITE, null, null))); // LeftMargin And RightMargin HBox h = new HBox(); h.prefWidthProperty().bind(widthProperty().divide(20)); h.setFillHeight(true); HBox h2 = new HBox(); h2.prefWidthProperty().bind(widthProperty().divide(20)); h2.setFillHeight(true); // StackPane: Center panel, z:0 CorticalLogoPane, z:1 VBox w/main content StackPane stack = new StackPane(); stack.prefWidthProperty().bind(widthProperty().multiply(9.0/10.0)); stack.prefHeightProperty().bind(heightProperty()); ////////////////////////////// // Z:0 background logo // ////////////////////////////// CorticalLogoBackground backGround = new CorticalLogoBackground(stack); backGround.setOpacity(0.2); ////////////////////////////// // Z:1 Main Content in VBox // ////////////////////////////// VBox vBox = new VBox(); vBox.setSpacing(20); vBox.prefWidthProperty().bind(stack.widthProperty()); vBox.prefHeightProperty().bind(new SimpleDoubleProperty(100.0)); LogoTitlePane header = new LogoTitlePane(); header.setTitleText("Breaking News"); header.setSubTitleText("a Twitter trend tracking demo..."); HBox buttonBar = createSegmentedButtonBar(); DualPanel inputPane = createInputPane(); inputPane.panelHeightProperty().setValue(105); LabelledRadiusPane chartPane = new LabelledRadiusPane("Trend"); chartPane.getChildren().add(createChart(chartPane)); SegmentedButtonBar log = createShowLogButton(vBox); BorderPane logButton = new BorderPane(); logButton.prefWidthProperty().bind(vBox.widthProperty()); logButton.setPrefHeight(10); logButton.setCenter(log); TriplePanel fpDisplay = createFingerprintDisplay(); LabelledRadiusPane loggerPane = createActivityPane(); loggerPane.prefWidthProperty().bind(fpDisplay.widthProperty()); loggerPane.prefHeightProperty().bind(fpDisplay.heightProperty()); RadiusFlipPane flip = new RadiusFlipPane(fpDisplay, loggerPane); fpDisplay.prefWidthProperty().bind(vBox.widthProperty()); flipPaneProperty.set(flip); vBox.getChildren().addAll(header, buttonBar, inputPane, chartPane, logButton, flip); stack.getChildren().addAll(backGround, vBox); // Main Layout: 3 columns, 1 row add(h, 0, 0); add(stack, 1, 0); add(h2, 2, 0); } public SegmentedButtonBar createShowLogButton(VBox vBox) { Button logButton = new Button("Show Activity"); logButton.getStyleClass().add("only"); logButton.setStyle("-fx-font-size: 10; -fx-padding: 4 12 4 12; -fx-height: 10;"); logButton.setPrefHeight(10); logButton.setPrefWidth(150); vBox.widthProperty().addListener((v, o, n) -> { logButton.setLayoutX(n.doubleValue() / 2.0 - 75); }); logButton.setOnAction(e -> { flipStateProperty.set(state = state == FlipState.ON_FRONT ? FlipState.ON_BACK : FlipState.ON_FRONT); logButton.setText(state == FlipState.ON_FRONT ? "Show Activity" : "Show Fingerprints"); }); SegmentedButtonBar buttonBar3 = new SegmentedButtonBar(); buttonBar3.getChildren().addAll(logButton); buttonBar3.setPrefHeight(10); return buttonBar3; } public TriplePanel createFingerprintDisplay() { // Left and Right panes of DualPanel LabelledRadiusPane left2 = createFingerprintPane("Fingerprint"); LabelledRadiusPane middle2 = createFingerprintPane("Comparison"); LabelledRadiusPane right2 = createFingerprintPane("Prediction"); ((FingerprintPane)right2).setColorIndex(1); TriplePanel fpDisplay = new TriplePanel(); fpDisplay.setSpacing(10); fpDisplay.panelHeightProperty().setValue(435); fpDisplay.setLeftPane(left2); fpDisplay.setMiddlePane(middle2); fpDisplay.setRightPane(right2); fingerprintPanelProperty.set(fpDisplay); return fpDisplay; } public DualPanel createInputPane() { DualPanel retVal = new DualPanel(); LabelledRadiusPane left = new LabelledRadiusPane("Input Tweet"); TextArea lArea = new TextArea(); lArea.setWrapText(true); lArea.setFont(Font.font("Helvetica", FontWeight.MEDIUM, 16)); lArea.layoutYProperty().bind(left.labelHeightProperty().add(10)); left.layoutBoundsProperty().addListener((v, o, n) -> { lArea.setLayoutX(10); lArea.setPrefWidth(n.getWidth() - 20); lArea.setPrefHeight(n.getHeight() - left.labelHeightProperty().get() - 20); }); Label queueLabel = new Label("Processing Queue Size:"); queueLabel.layoutXProperty().bind(lArea.widthProperty().subtract(queueLabel.getLayoutBounds().getWidth() + 330)); queueLabel.setLayoutY(lArea.getLayoutY() - queueLabel.getLayoutBounds().getHeight() - 35); queueLabel.setFont(Font.font("Helvetica", FontWeight.BOLD, 12)); queueLabel.setTextFill(Color.rgb(00, 70, 107)); queueDisplayProperty.set(queueLabel); Label curLabel = new Label("Current Tweet:"); curLabel.layoutXProperty().bind(lArea.widthProperty().subtract(curLabel.getLayoutBounds().getWidth() + 110)); curLabel.setLayoutY(lArea.getLayoutY() - curLabel.getLayoutBounds().getHeight() - 35); curLabel.setFont(Font.font("Helvetica", FontWeight.BOLD, 12)); curLabel.setTextFill(Color.rgb(00, 70, 107)); currentLabelProperty.set(curLabel.textProperty()); left.getChildren().addAll(lArea, queueLabel, curLabel); LabelledRadiusPane right = new LabelledRadiusPane("Scrubbed Tweet"); TextArea rArea = new TextArea(); rArea.setWrapText(true); rArea.setFont(Font.font("Helvetica", FontWeight.MEDIUM, 16)); rArea.layoutYProperty().bind(right.labelHeightProperty().add(10)); right.layoutBoundsProperty().addListener((v, o, n) -> { rArea.setLayoutX(10); rArea.setPrefWidth(n.getWidth() - 20); rArea.setPrefHeight(n.getHeight() - right.labelHeightProperty().get() - 20); }); right.getChildren().add(rArea); retVal.setLeftPane(left); retVal.setRightPane(right); inputPaneProperty.set(new Pair<>(lArea, rArea)); return retVal; } /** * Demonstrates the construction and usage of the {@link SegmentedButtonBar} * @return */ public HBox createSegmentedButtonBar() { ToggleButton button1 = new ToggleButton("Start"); button1.getStyleClass().addAll("first"); button1.setOnAction(e -> { Platform.runLater(() -> { if(mode == Mode.MANUAL) { runOneBtn.setDisable(false); } startActionProperty.set(true); }); }); ToggleButton button2 = new ToggleButton("Stop"); button2.getStyleClass().addAll("last"); button2.setOnAction(e -> { Platform.runLater(() -> { startActionProperty.set(false); }); }); ToggleButton button3 = new ToggleButton("Auto"); button3.getStyleClass().addAll("first"); button3.setOnAction(e -> { Platform.runLater(() -> { mode = Mode.AUTO; autoModeProperty.set(mode); }); }); ToggleButton button4 = new ToggleButton("Manual"); button4.getStyleClass().addAll("last"); button4.setOnAction(e -> { Platform.runLater(() -> { mode = Mode.MANUAL; autoModeProperty.set(mode); }); }); Button button5 = runOneBtn = new Button("Run One"); button5.getStyleClass().addAll("only"); button5.setDisable(true); button5.setOnAction(e -> { Platform.runLater(() -> { runOneProperty.set(runOneProperty.get() + 1); }); }); runDisableProperty.addListener((v, o, n) -> { button5.setDisable(n); }); ToggleGroup group = new ToggleGroup(); group.getToggles().addAll(button1, button2); group.selectToggle(button2); ToggleGroup group2 = new ToggleGroup(); group2.getToggles().addAll(button3, button4); group2.selectToggle(button3); group2.selectedToggleProperty().addListener((v, o, n) -> { if(n == null) return; if(n.equals(button4)) { Platform.runLater(() -> { mode = Mode.MANUAL; group.selectToggle(button2); startActionProperty.set(false); }); }else{ Platform.runLater(() -> { mode = Mode.AUTO; startActionProperty.set(false); group.selectToggle(button2); button5.setDisable(true); }); } }); HBox displayBox = new HBox(); displayBox.setSpacing(20); displayBox.setAlignment(Pos.CENTER); SegmentedButtonBar buttonBar = new SegmentedButtonBar(); buttonBar.getChildren().addAll(button1, button2); SegmentedButtonBar buttonBar2 = new SegmentedButtonBar(); buttonBar2.getChildren().addAll(button3, button4); SegmentedButtonBar buttonBar3 = new SegmentedButtonBar(); buttonBar3.getChildren().addAll(button5); displayBox.getChildren().addAll(buttonBar, buttonBar2, buttonBar3); return displayBox; } public LineChart<String, Number> createChart(LabelledRadiusPane pane) { CategoryAxis xAxis = new CategoryAxis(); NumberAxis yAxis = new NumberAxis(); chart = new LineChart<>(xAxis, yAxis); chart.setTitle("Tweet Trend Analysis"); chart.setCreateSymbols(false); chart.setLegendVisible(false); xAxis.setLabel("Time of Tweet"); yAxis.setUpperBound(1.0); yAxis.setLowerBound(0.0); yAxis.setLabel("Anomaly\n Score"); yAxis.setForceZeroInRange(true); series = new XYChart.Series<>(); series.setName("Tweet Data"); chart.getData().add(series); chartSeriesProperty.set(series); Node line = series.getNode().lookup(".chart-series-line"); line.setStyle("-fx-stroke: rgb(20, 164, 220)"); chart.setPrefWidth(1200); chart.setPrefHeight(275); chart.setLayoutY(pane.labelHeightProperty().get() + 10); return chart; } /** * Creates the monitor view * @return */ public LabelledRadiusPane createActivityPane() { LabelledRadiusPane retVal = new LabelledRadiusPane("Activity Monitor"); HBox h = new HBox(); h.setFillHeight(true); h.setSpacing(15); h.setPadding(new Insets(0, 10, 10, 15)); h.prefWidthProperty().bind(retVal.widthProperty()); h.layoutYProperty().bind(retVal.labelHeightProperty().add(20)); TextArea area = new TextArea(); area.prefWidthProperty().bind(h.widthProperty().subtract(30).divide(2)); area.prefHeightProperty().bind(retVal.heightProperty().subtract(60)); area.setLayoutY(retVal.labelHeightProperty().add(0).get()); leftActivityPanelProperty.set(area); TextArea area2 = new TextArea(); area2.prefWidthProperty().bind(h.widthProperty().subtract(60).divide(2)); area2.prefHeightProperty().bind(retVal.heightProperty().subtract(60)); area2.setLayoutY(retVal.labelHeightProperty().add(0).get()); area2.textProperty().addListener((v, o, n) -> { area2.setScrollTop(Double.MAX_VALUE); area2.setScrollLeft(Double.MAX_VALUE); }); rightActivityPanelProperty.set(area2); h.getChildren().addAll(area, area2); Label l = new Label("Output"); l.setFont(Font.font("Helvetica", FontWeight.BOLD, 14)); l.setTextFill(Color.rgb(00, 70, 107)); l.layoutXProperty().bind(area.widthProperty().divide(2).add(area.getLayoutX()).subtract(l.getWidth())); l.setLayoutY(area.getLayoutY() - l.getHeight()); Label l2 = new Label("Similar Tweets"); l2.setFont(Font.font("Helvetica", FontWeight.BOLD, 14)); l2.setTextFill(Color.rgb(00, 70, 107)); area2.layoutBoundsProperty().addListener((v, o, n) -> { l2.setLayoutX(area.getWidth() + 60 + area2.getWidth() / 2 - l2.getWidth()); }); l2.setLayoutY(area2.getLayoutY() - l.getHeight()); retVal.getChildren().addAll(h, l, l2); return retVal; } public FingerprintPane createFingerprintPane(String text) { FingerprintPane pane = new FingerprintPane(); pane.setLabelText(text); return pane; } public ObjectProperty<XYChart.Series<String, Number>> chartSeriesProperty() { return chartSeriesProperty; } public BooleanProperty startActionProperty() { return startActionProperty; } public ObjectProperty<Mode> autoModeProperty() { return autoModeProperty; } public IntegerProperty runOneProperty() { return runOneProperty; } public BooleanProperty runDisableProperty() { return runDisableProperty; } public ObjectProperty<Pair<TextArea, TextArea>> inputPaneProperty() { return inputPaneProperty; } public ObjectProperty<RadiusFlipPane> flipPaneProperty() { return flipPaneProperty; } public ObjectProperty<FlipState> flipStateProperty() { return flipStateProperty; } public ObjectProperty<TriplePanel> fingerprintPanelProperty() { return fingerprintPanelProperty; } public ObjectProperty<TextArea> leftActivityPanelProperty() { return leftActivityPanelProperty; } public ObjectProperty<TextArea> rightActivityPanelProperty() { return rightActivityPanelProperty; } public ObjectProperty<StringProperty> currentLabelProperty() { return currentLabelProperty; } public ObjectProperty<Label> queueDisplayProperty() { return queueDisplayProperty; } }